home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Aminet 1 (Walnut Creek)
/
Aminet - June 1993 [Walnut Creek].iso
/
usenet
/
sources
/
volume89
/
aplictns
/
graph.4
< prev
next >
Wrap
Internet Message Format
|
1989-11-13
|
59KB
Path: xanth!lll-winken!uunet!wuarchive!texbell!texsun!newstop!sun!swap!page
From: page%swap@Sun.COM (Bob Page)
Newsgroups: comp.sources.amiga
Subject: v89i207: graph - plot mathematical functions, Part04/07
Message-ID: <127785@sun.Eng.Sun.COM>
Date: 13 Nov 89 02:32:34 GMT
Sender: news@sun.Eng.Sun.COM
Lines: 1878
Approved: page@sun.com
Submitted-by: dg3i+@andrew.cmu.edu (David Gay)
Posting-number: Volume 89, Issue 207
Archive-name: applications/graph.4
# This is a shell archive.
# Remove anything above and including the cut line.
# Then run the rest of the file through 'sh'.
# Unpacked files will be owned by you and have default permissions.
#----cut here-----cut here-----cut here-----cut here----#
#!/bin/sh
# shar: SHell ARchive
# Run the following text through 'sh' to create:
# graphics.h
# grph.c
# This is archive 4 of a 7-part kit.
# This archive created: Sun Nov 12 18:23:30 1989
echo "extracting graphics.h"
sed 's/^X//' << \SHAR_EOF > graphics.h
X/*
X * GRAPH, Version 1.00 - 4 August 1989
X *
X * Copyright 1989, David Gay. All Rights Reserved.
X * This software is freely redistrubatable.
X */
X
X/* Various graphic extensions */
X#ifndef BIG_GRAPHICS_H
X#define BIG_GRAPHICS_H
X
X/* Now, where did I get this idea ??? */
Xstruct TextExtent {
X UWORD te_Width;
X UWORD te_Height;
X struct Rectangle te_Extent;
X};
X
X/* Draw a line longer than 1008 pixels */
Xvoid BigDraw(struct RastPort *rp, long x, long y);
X/* Idem, but take account of PenWidth, PenHeight (must be odd) */
Xvoid ThickDraw(struct RastPort *rp, long x, long y);
X/* Only works for rastport's with no clipping */
Xvoid BigSetRast(struct RastPort *rp, long colour);
X/* Determine real extent of text(-> Rectangle), return it in TextExtent ext */
Xvoid TextExtent(char *text, struct TextFont *font, struct TextExtent *ext);
X
X#endif
X
SHAR_EOF
echo "extracting grph.c"
sed 's/^X//' << \SHAR_EOF > grph.c
X/*
X * GRAPH, Version 1.00 - 4 August 1989
X *
X * Copyright 1989, David Gay. All Rights Reserved.
X * This software is freely redistrubatable.
X */
X
X/* Graph manipulation */
X
X#include <exec/types.h>
X#include <graphics/gfxbase.h>
X#include <graphics/rastport.h>
X#include <intuition/intuition.h>
X#include <devices/prtbase.h>
X#include <devices/printer.h>
X#include <stdio.h>
X#include <string.h>
X#include <math.h>
X#include <limits.h>
X#include <iff/iff.h>
X#include <iff/ilbm.h>
X
X#include "grph.h"
X#include "file.h"
X#include "graphics.h"
X#include "graph.h"
X#include "uio.h"
X#include "object.h"
X#include "list.h"
X#include "coords.h"
X#include "user/gadgets.h"
X#include "tracker.h"
X
X#include <proto/exec.h>
X#include <proto/graphics.h>
X#include <proto/diskfont.h>
X#include <proto/intuition.h>
X
X#define INCH 2.54e-2
X#define DIGHEIGHT 8 /* Digit font size, in points (1 point = 1/72 inch) */
X#define XTICK 0.05 /* Size of tick for X axis, In inches */
X#define YTICK 0.05
X#define XTEXT 0.12
X#define YTEXT 0.09
X
X#define MAXPRINTPAGES 1 /* Max length for printing */
X#define CHOOSELIST 2 /* for choose req */
X#define IFFDISK 2 /* For iff req */
X
X/* A function to send a slice of output to the chosen device (disk/file) */
Xtypedef int (*prtfunc)(struct graph *g, struct RastPort *rp, int w, int h, int
Xy, int slice, struct Requester *abreq);
X
Xextern struct GfxBase *GfxBase;
X
Xstatic UWORD scr_dpmx, scr_dpmy; /* The screen 'resolution' */
X
X/* Data for printer output */
Xstatic struct IODRPReq *prtio;
Xstatic struct MsgPort *prtport;
Xstatic struct PrinterExtendedData *ped;
Xstatic struct Preferences *prtprefs;
Xstatic struct ColorMap *prtcm;
X
X/* Data for iff output */
Xstatic FILE *iff_file;
Xstatic long form_pos, body_pos;
Xstatic char iff_filename[FILELEN];
Xstatic struct Gadget *iffg;
X
Xstatic char *prt_error[] = {
X "Unknown error",
X "Print cancelled",
X "Not a graphics printer !",
X "Obsolete",
X "Illegal print dimensions",
X "Obsolete",
X "No memory (internal)",
X "No memory (for buffers)"
X};
X
X#define MAX_PRT_ERROR (sizeof(prt_error) / sizeof(char *) - 1)
X
X/* Check that ax can be displayed */
Xstatic int ax_ok(const struct ax *a, const struct ax *other)
X{
X return (a->ax == NOVAL ||
X ((!other->log || a->ax > 0.0) &&
X (a->cstep == NOVAL ||
X (a->cstep > 0.0 &&
X (a->every == INOVAL || a->every > 0)))));
X}
X
X/* Check that ax has legal values */
Xstatic int ax_ok2(const struct ax *a)
X{
X return a->min != NOVAL && a->max != NOVAL && a->min < a->max &&
X (!a->log || a->min > 0.0);
X}
X
X/* Check if graph is displayable */
Xstatic int graph_ok(struct graph *g)
X{
X g->a.ok = ax_ok(&g->a.x, &g->a.y) && ax_ok(&g->a.y, &g->a.x) &&
X (g->a.ratio == NOVAL || g->a.ratio > 0.0);
X
X return ax_ok2(&g->a.x) && ax_ok2(&g->a.x);
X}
X
X/* Redraw graph after changes */
Xstatic void check_graph(struct graph *g)
X{
X g->saved = FALSE;
X g->ok = graph_ok(g);
X set_scale(g);
X draw_graph(g, TRUE);
X}
X
X/* Find object in graph by name */
Xstatic struct object *find_object(struct graph *g, char *name)
X{
X struct object *o;
X
X for (o = first(&g->o_list); succ(o); o = succ(o))
X if (strcmp(o->name, name) == 0) return o;
X
X return NULL;
X}
X
X/* Convert inches to rastport dots, using current dpm */
X/* Use integer arithmetic if needs to be called often */
Xint xinch2dots(struct graph *g, double x)
X{
X return (int)(x * INCH * g->io.dpmx + 0.5);
X}
X
Xint yinch2dots(struct graph *g, double y)
X{
X return (int)(y * INCH * g->io.dpmy + 0.5);
X}
X
X/* Open font in pts points */
Xstruct TextFont *open_font(struct graph *g, char *name, int pts, int style, int
X flags)
X{
X struct TextAttr ta;
X struct TextFont *tf1, *tf2;
X
X ta.ta_Name = name;
X ta.ta_YSize = yinch2dots(g, pts / 72.0);
X ta.ta_Style = style;
X ta.ta_Flags = flags;
X
X tf1 = OpenFont(&ta);
X if (!tf1)
X return OpenDiskFont(&ta);
X else if (tf1->tf_YSize != ta.ta_YSize)
X {
X tf2 = OpenDiskFont(&ta);
X
X if (tf2)
X {
X CloseFont(tf1);
X return tf2;
X }
X else
X return tf2;
X }
X else
X return tf1;
X}
X
X/* add object to graph (object is already displayed) */
Xstruct object *add_object(struct graph *g, struct object *o)
X{
X if (o)
X {
X if (o->name[0] != '\0' && find_object(g, o->name))
X {
X message(g, "Name already used", (char *)NULL);
X refresh_graph(g, TRUE, o->delete(o));
X return NULL;
X }
X add_head(&g->o_list, o);
X g->saved = FALSE;
X }
X return o;
X}
X
X/* Remove object & redisplay graph */
Xvoid remove_object(struct graph *g, struct object *o)
X{
X if (o == g->s.current)
X {
X o->deselect(o);
X g->s.current = NULL;
X disable_rect_menus(g);
X disable_object_menus(g);
X }
X remove(o);
X g->saved = FALSE;
X refresh_graph(g, TRUE, o->delete(o));
X}
X
X/* Make object o selected */
Xvoid select_object(struct graph *g, struct object *o)
X{
X if (o)
X {
X g->s.current = o;
X o->select(o); /* Inform object of this */
X enable_object_menus(g);
X set_title(g);
X }
X}
X
X/* Deslect current object */
Xvoid deselect(struct graph *g)
X{
X struct Region *ref;
X
X /* Deselect object */
X ref = g->s.current ? g->s.current->deselect(g->s.current) : NULL;
X g->s.current = NULL;
X
X disable_rect_menus(g);
X disable_object_menus(g);
X refresh_graph(g, TRUE, ref);
X}
X
X/* User pressed mouse button */
Xvoid mouse_down(struct graph *g, WORD sx, WORD sy)
X{
X if (g->ok && g->io.rw)
X {
X /* Get real pos */
X g->s.x = g->io.rw->x(g->io.rw, sx);
X g->s.y = g->io.rw->y(g->io.rw, sy);
X /* If nothing selected, or if not clicking in selected object */
X if (!g->s.current || !g->s.current->down(g->s.current))
X {
X deselect(g);
X
X if (g->s.select_mode) /* Try to select something */
X {
X struct object *o;
X
X for (o = first(&g->o_list); succ(o); o = succ(o))
X if (o->down(o)) /* Inside object ? */
X {
X select_object(g, o);
X break; /* exit for loop */
X }
X }
X else /* Start a new rectangle */
X if (g->s.current = (struct object *)new_pos(g))
X enable_rect_menus(g);
X
X }
X if (g->s.current) /* Something is now selected, keep track of mouse */
X {
X /* Adjust position for offset in object */
X g->s.x = g->io.rw->x(g->io.rw, sx - g->s.current->mx);
X g->s.y = g->io.rw->y(g->io.rw, sy - g->s.current->my);
X ReportMouse(g->io.win, TRUE);
X g->s.mouse = TRUE;
X }
X set_title(g);
X }
X}
X
X/* Mouse has moved */
Xvoid mouse_move(struct graph *g, WORD sx, WORD sy)
X{
X if (g->s.mouse)
X {
X /* Adjust for offset, calc pos in coord system */
X sx -= g->s.current->mx;
X sy -= g->s.current->my;
X g->s.x = g->io.rw->x(g->io.rw, sx);
X g->s.y = g->io.rw->y(g->io.rw, sy);
X
X /* Inform selection of movement */
X g->s.current->move(g->s.current);
X
X set_title(g);
X }
X}
X
X/* Mouse button released */
Xvoid mouse_up(struct graph *g, WORD sx, WORD sy)
X{
X if (g->s.mouse) /* mouse was down */
X {
X g->saved = FALSE; ./* Graph has very probably changed */
X g->s.mouse = FALSE;
X
X sx -= g->s.current->mx;
X sy -= g->s.current->my;
X g->s.x = g->io.rw->x(g->io.rw, sx);
X g->s.y = g->io.rw->y(g->io.rw, sy);
X
X ReportMouse(g->io.win, FALSE);
X /* Redaw whatever is necessary */
X refresh_graph(g, TRUE, g->s.current->up(g->s.current));
X }
X}
X
X/* Handler for object selection requester */
Xstatic int choose_handler(struct Gadget *gg, ULONG class, struct Requester *req
X, struct graph *g)
X{
X if (gg->GadgetID == CHOOSELIST) /* In a list */
X {
X if (ModifyList(gg, req, req->RWindow, class == GADGETUP) == 2)
X {
X EndRequest(req, req->RWindow);
X return TRUE;
X }
X }
X else return std_ghandler(gg, class, req, g);
X}
X
X/* Ask user to choose an object, by name */
Xstruct object *choose_object(struct graph *g, char *op)
X{
X struct object *o, *sel = NULL;
X char name[FNAMELEN];
X tlist l;
X char what[30];
X int ok;
X
X /* Construct title */
X what[29] = '\0'; name[0] = '\0';
X strncpy(what, op, 29);
X strncat(what, " function", 29 - strlen(what));
X
X /* Construct list of named objects */
X new_list(&l);
X ok = TRUE;
X for (o = first(&g->o_list); succ(o); o = succ(o))
X if (o->name[0] != '\0')
X {
X tnode *n = alloc_node(sizeof(tnode));
X
X if (!n)
X {
X ok = FALSE;
X break;
X }
X n->ln_Name = o->name;
X add_tail(&l, n);
X }
X
X if (ok) /* list constructed ok */
X {
X /* Create requester */
X struct Requester *req;
X struct Memory *m;
X struct Gadget *gl = NULL;
X
X if ((m = NewMemory()) &&
X (req = InitReq(50, 20, 200, 120, m)) &&
X SetReqBorder(req, 1, m) &&
X AddIntuiText(&req->ReqText, what, 100 - 4 * strlen(what), 6, m) &&
X AddList(&gl, CHOOSELIST, "Name", &l, name, FNAMELEN, 0, RELVERIFY |
X ENDGADGET, 20, 20, 160, 80, TRUE, m) &&
X AddBox(&gl, TRUE, "Ok", 0, RELVERIFY | ENDGADGET, 18, 95, 65, 15, F
XALSE, m) &&
X AddBox(&gl, FALSE, "Cancel", 0, RELVERIFY | ENDGADGET, 118, 95, 65,
X 15, FALSE, m))
X {
X SetReqGadgets(req, gl);
X if (DoRequest(req, g, choose_handler))
X {
X /* Remove blanks */
X strip(name);
X if (*name)
X {
X sel = find_object(g, name);
X if (!sel) message(g, "No such function", (char *)NULL);
X }
X }
X }
X Free(m);
X }
X free_list((list *)&l, sizeof(tnode));
X return sel;
X}
X
X/* Define coordinate system */
Xvoid enter_limits(struct graph *g)
X{
X struct Requester *req;
X struct Memory *m;
X struct Gadget *gl = NULL, *x_log, *y_log;
X char xmin[NBLEN], xmax[NBLEN], ymin[NBLEN], ymax[NBLEN], ratio[NBLEN];
X
X double2str(xmin, g->a.x.min);
X double2str(xmax, g->a.x.max);
X double2str(ymin, g->a.y.min);
X double2str(ymax, g->a.y.max);
X double2str(ratio, g->a.ratio);
X
X if ((m = NewMemory()) &&
X (req = InitReq(50, 20, 325, 105, m)) &&
X SetReqBorder(req, 1, m) &&
X AddIntuiText(&req->ReqText, "Limits", 138, 6, m) &&
X AddText(&gl, 0, "X: Min ", FALSE, xmin, NBLEN, TRUE, 0, RELVERIFY, 67,
X20, 80, 10, TRUE, m) &&
X AddText(&gl, 0, "Max ", FALSE, xmax, NBLEN, TRUE, 0, RELVERIFY, 190, 20
X, 80, 10, TRUE, m) &&
X (x_log = AddOption(&gl, 0, "Log", FALSE, g->a.x.log * SELECTED, 0, 305,
X 20, 10, 10, m)) &&
X AddText(&gl, 0, "Y: Min ", FALSE, ymin, NBLEN, TRUE, 0, RELVERIFY, 67,
X40, 80, 10, TRUE, m) &&
X AddText(&gl, 0, "Max ", FALSE, ymax, NBLEN, TRUE, 0, RELVERIFY, 190, 40
X, 80, 10, TRUE, m) &&
X (y_log = AddOption(&gl, 0, "Log", FALSE, g->a.y.log * SELECTED, 0, 305,
X 40, 10, 10, m)) &&
X AddText(&gl, 0, "Ratio (Y/X) ", FALSE, ratio, NBLEN, TRUE, 0, RELVERIFY
X, 107, 60, 80, 10, TRUE, m) &&
X AddBox(&gl, TRUE, "Ok", 0, RELVERIFY | ENDGADGET, 49, 80, 65, 15, FALSE
X, m) &&
X AddBox(&gl, FALSE, "Cancel", 0, RELVERIFY | ENDGADGET, 211, 80, 65, 15,
X FALSE, m))
X {
X SetReqGadgets(req, gl);
X if (DoRequest(req, g, std_ghandler))
X {
X g->a.x.min = str2double(xmin);
X g->a.x.max = str2double(xmax);
X g->a.x.log = (x_log->Flags & SELECTED) != 0;
X g->a.y.min = str2double(ymin);
X g->a.y.max = str2double(ymax);
X g->a.y.log = (y_log->Flags & SELECTED) != 0;
X g->a.ratio = str2double(ratio);
X check_graph(g);
X }
X }
X Free(m);
X}
X
X/* Choose axes display options */
Xvoid enter_axes(struct graph *g)
X{
X struct Requester *req;
X struct Memory *m;
X struct Gadget *gl = NULL;
X char ax_x[NBLEN], ax_y[NBLEN], step_x[NBLEN], step_y[NBLEN],
X every_x[INTLEN], every_y[INTLEN];
X
X double2str(ax_x, g->a.x.ax);
X double2str(step_x, g->a.x.cstep);
X int2str(every_x, g->a.x.every);
X double2str(ax_y, g->a.y.ax);
X double2str(step_y, g->a.y.cstep);
X int2str(every_y, g->a.y.every);
X
X if ((m = NewMemory()) &&
X (req = InitReq(50, 15, 225, 165, m)) &&
X SetReqBorder(req, 1, m) &&
X AddIntuiText(&req->ReqText, "Axes", 96, 6, m) &&
X AddText(&gl, 0, "X: Axe at ", FALSE, ax_x, NBLEN, TRUE, 0, RELVERIFY, 9
X1, 20, 80, 10, TRUE, m) &&
X AddText(&gl, 0, " Ticks every ", FALSE, step_x, NBLEN, TRUE, 0, RELVE
XRIFY, 131, 40, 80, 10, TRUE, m) &&
X AddText(&gl, 0, " numbered every ", FALSE, every_x, INTLEN, TRUE, 0,
XRELVERIFY, 155, 60, 32, 10, TRUE, m) &&
X AddText(&gl, 0, "Y: Axe at ", FALSE, ax_y, NBLEN, TRUE, 0, RELVERIFY, 9
X1, 80, 80, 10, TRUE, m) &&
X AddText(&gl, 0, " Ticks every ", FALSE, step_y, NBLEN, TRUE, 0, RELVE
XRIFY, 131, 100, 80, 10, TRUE, m) &&
X AddText(&gl, 0, " numbered every ", FALSE, every_y, INTLEN, TRUE, 0,
XRELVERIFY, 155, 120, 32, 10, TRUE, m) &&
X AddBox(&gl, TRUE, "Ok", 0, RELVERIFY | ENDGADGET, 24, 140, 65, 15, FALS
XE, m) &&
X AddBox(&gl, FALSE, "Cancel", 0, RELVERIFY | ENDGADGET, 136, 140, 65, 15
X, FALSE, m))
X {
X SetReqGadgets(req, gl);
X if (DoRequest(req, g, std_ghandler))
X {
X g->a.x.ax = str2double(ax_x);
X g->a.x.cstep = str2double(step_x);
X g->a.x.every = str2int(every_x);
X g->a.y.ax = str2double(ax_y);
X g->a.y.cstep = str2double(step_y);
X g->a.y.every = str2int(every_y);
X check_graph(g);
X }
X }
X Free(m);
X}
X
X/* Change mode */
Xvoid set_mode(struct graph *g, int newmode)
X{
X if (newmode != g->s.select_mode) deselect(g);
X g->s.select_mode = newmode;
X}
X
X/* Recalc & display title */
X/* assumes GNAMELEN < TITLELEN */
Xvoid set_title(struct graph *g)
X{
X strcpy(g->io.title, g->name);
X if (!g->ok) strncat(g->io.title, "(Bad)", TITLELEN - 1 - strlen(g->io.title
X));
X if (g->s.current)
X if (g->s.current->name[0] != '\0')
X {
X strncat(g->io.title, ", function is ", TITLELEN - 1 - strlen(g->io.
Xtitle));
X strncat(g->io.title, g->s.current->name, TITLELEN - 1 - strlen(g->i
Xo.title));
X if (!g->s.current->ok) strncat(g->io.title, "(Bad)", TITLELEN - 1 -
X strlen(g->io.title));
X }
X else strncat(g->io.title, ", object selected", TITLELEN -1 - strlen(g->
Xio.title));
X else strncat(g->io.title, ", nothing selected", TITLELEN - 1 - strlen(g->io
X.title));
X if (g->s.mouse)
X {
X char x[NBLEN], y[NBLEN];
X
X double2str(x, g->s.x); double2str(y, g->s.y);
X strncat(g->io.title, " x=", TITLELEN - 1 - strlen(g->io.title));
X strncat(g->io.title, x, TITLELEN - 1 - strlen(g->io.title));
X strncat(g->io.title, ", y=", TITLELEN - 1 - strlen(g->io.title));
X strncat(g->io.title, y, TITLELEN - 1 - strlen(g->io.title));
X }
X
X SetWindowTitles(g->io.win, g->io.title, "Graph");
X}
X
X/* Window has changed size, recreate coord system, taking into account the
X desired ratio */
Xvoid set_scale(struct graph *g)
X{
X /* Standard borders */
X long x0offset = g->io.win->BorderLeft + 8;
X long x1offset = g->io.win->BorderRight + 8;
X long y0offset = g->io.win->BorderBottom + 8;
X long y1offset = g->io.win->BorderTop + 8;
X
X /* Save size used */
X g->io.oldwidth = g->io.win->Width; g->io.oldheight = g->io.win->Height;
X
X /* Delete old coords */
X if (g->io.rw) g->io.rw->delete(g->io.rw);
X
X /* Create new coords at max size */
X g->io.rw = new_RWindow(g->io.win->RPort, g->io.win->Width, g->io.win->Heigh
Xt,
X x0offset, y0offset, x1offset, y1offset,
X g->a.x.min, g->a.y.min, g->a.x.max, g->a.y.max,
X g->a.x.log, g->a.y.log, TRUE);
X if (!g->io.rw)
X {
X message(g, "Couldn't make coords", (char *)NULL);
X return;
X }
X
X SetRast(g->io.win->RPort, 0); /* Clear whole window */
X
X if (g->ok && g->a.ok && g->a.ratio != NOVAL)
X {
X /* Adjust for desired ratio */
X double r;
X
X /* Current ratio */
X r = g->a.ratio /
X fabs(((g->io.rw->sy(g->io.rw, g->a.y.log ? 10.0 : 2.0) - g->io.rw->
Xsy(g->io.rw, 1.0)) * scr_dpmx) /
X ((g->io.rw->sx(g->io.rw, g->a.x.log ? 10.0 : 2.0) - g->io.rw->
Xsx(g->io.rw, 1.0)) * scr_dpmy));
X
X g->io.rw->delete(g->io.rw);
X
X /* Adjust borders */
X if (r > 1.0) /* make X smaller */
X {
X long width = g->io.win->Width - x0offset - x1offset;
X long delta = width - width / r;
X
X x0offset += delta / 2;
X x1offset += delta - delta / 2;
X }
X else /* make Y smaller */
X {
X long height = g->io.win->Height - y0offset - y1offset;
X long delta = height - height * r;
X
X y0offset += delta / 2;
X y1offset += delta - delta / 2;
X }
X /* & create new coord system */
X g->io.rw = new_RWindow(g->io.win->RPort, g->io.win->Width, g->io.win->H
Xeight,
X x0offset, y0offset, x1offset, y1offset,
X g->a.x.min, g->a.y.min, g->a.x.max, g->a.y.max,
X g->a.x.log, g->a.y.log, TRUE);
X if (!g->io.rw)
X {
X message(g, "Couldn't make coords", (char *)NULL);
X return;
X }
X }
X}
X
X/* Change output resolution.
X This may require opening of new resources (eg fonts) in the objects, which
X can obviously fail, yet we don't want the graph to be left in an inconsis-
X tent state, hence inform & confirm (cf object.guidelines). */
Xint set_dpm(struct graph *g, int dpmx, int dpmy)
X{
X int olddpmx = g->io.dpmx, olddpmy = g->io.dpmy;
X struct TextFont *digits;
X
X g->io.dpmx = dpmx; g->io.dpmy = dpmy;
X /* Open correct font for this resolution */
X if (digits = open_font(g, "digits.font", DIGHEIGHT, 0, 0))
X {
X int ok = TRUE;
X struct object *scan, *scan2;
X
X /* Inform objects */
X for (scan = first(&g->o_list); ok && succ(scan); scan = succ(scan))
X if (!scan->inform(scan)) ok = FALSE;
X
X if (ok)
X {
X /* Everything worked, confoirm changes */
X for (scan = first(&g->o_list); ok && succ(scan); scan = succ(scan))
X
X scan->confirm(scan, TRUE);
X
X /* Free old resources */
X CloseFont(g->io.digits);
X g->io.digits = digits;
X return TRUE;
X }
X /* Return to previous state */
X for (scan2 = first(&g->o_list); scan2 != scan; scan2 = succ(scan2))
X scan2->confirm(scan2, FALSE);
X
X CloseFont(digits);
X }
X else
X message(g, "Couldn't open digits.font", (char *)NULL);
X g->io.dpmx = olddpmx; g->io.dpmy = olddpmy;
X return FALSE;
X}
X
X /* Set pen to one ptsize wide. Should really modify g->io.rw->rp, but ... *
X/
Xvoid set_pensize(struct graph *g, struct RastPort *rp, double ptsize)
X{
X int xsize = xinch2dots(g, ptsize / 72.0);
X int ysize = yinch2dots(g, ptsize / 72.0);
X
X if ((xsize & 1) == 0) xsize++;
X if ((ysize & 1) == 0) ysize++;
X
X rp->PenWidth = xsize;
X rp->PenHeight = ysize;
X}
X
X/* Use a "thin" line (1 pixel wide) */
Xvoid set_thin(struct graph *g, struct RastPort *rp)
X{
X rp->PenWidth = 1;
X rp->PenWidth = 1;
X}
X
X/* Change graph limits */
Xvoid zoom_in(struct graph *g, double x0, double y0, double x1, double y1)
X{
X if (g->ok && x0 != x1 && y0 != y1)
X {
X double xmin = min(x0, x1);
X double xmax = max(x0, x1);
X double ymin = min(y0, y1);
X double ymax = max(y0, y1);
X
X g->a.x.min = max(g->a.x.min, xmin);
X g->a.x.max = min(g->a.x.max, xmax);
X g->a.y.min = max(g->a.y.min, ymin);
X g->a.y.max = min(g->a.y.max, ymax);
X
X check_graph(g);
X }
X else
X message(g, "No rectangle to zoom into", (char *)NULL);
X}
X
X/* Calculate new limits for ax a for a zoom factor of mult */
Xstatic void zoom_ax(struct ax *a, double mult)
X{
X if (a->log)
X {
X /* Zoom on a log scale ... Real fun with this one :-) */
X double centre = sqrt(a->min * a->max);
X double delta = pow(centre, 1.0 - mult);
X
X a->min = pow(a->min, mult) * delta;
X a->max = pow(a->max, mult) * delta;
X }
X else
X {
X /* ax becomes mult times longer, with same centre */
X double centre = (a->min + a->max) / 2;
X double delta = centre - a->min;
X
X a->min = centre - mult * delta;
X a->max = centre + mult * delta;
X }
X}
X
X/* Zoom out by a factor factor */
Xvoid zoom_factor(struct graph *g, double factor)
X{
X if (g->ok)
X {
X zoom_ax(&g->a.x, factor);
X zoom_ax(&g->a.y, factor);
X check_graph(g);
X }
X else
X message(g, "No scale set !", (char *)NULL);
X}
X
X/* Define new centre for ax */
Xstatic void center_ax(struct ax *a, double centre)
X{
X if (a->log)
X {
X /* more & more fun ... */
X double delta = sqrt(a->max / a->min);
X
X a->max = centre * delta;
X a->min = centre / delta;
X }
X else
X {
X /* obvious */
X double delta = (a->max - a->min) / 2.0;
X
X a->max = centre + delta;
X a->min = centre - delta;
X }
X}
X
X/* New centre for graph */
Xvoid center_graph(struct graph *g, double x, double y)
X{
X if (g->ok && x != NOVAL)
X {
X center_ax(&g->a.x, max(min(x, g->a.x.max), g->a.x.min));
X center_ax(&g->a.y, max(min(y, g->a.y.max), g->a.y.min));
X check_graph(g);
X }
X else
X message(g, "Nothing to center on", (char *)NULL);
X}
X
X/* Redraw ax a (of graph g), at position xorig on other ax. y_ax is true for
X drawing of y axis */
Xstatic void draw_ax(struct graph *g, struct ax *a, double xorig, int y_ax)
X{
X struct TextFont *oldfont, *digits = g->io.digits;
X struct RWindow *const rwin = g->io.rw;
X struct RastPort *const rp = rwin->rp;
X int xtick = yinch2dots(g, XTICK), ytick = xinch2dots(g, YTICK);
X int xtext = xinch2dots(g, XTEXT), ytext = yinch2dots(g, YTEXT);
X
X oldfont = rp->Font;
X SetFont(rp, digits);
X SetDrMd(rp, JAM1);
X if (a->ax != NOVAL)
X {
X /* Draw ax */
X if (y_ax)
X {
X RMove(rwin, a->ax, a->max);
X Draw(rwin->rp, rwin->rp->cp_x, ftol(rwin->sy(rwin, a->min)));
X }
X else
X {
X RMove(rwin, a->max, a->ax);
X Draw(rwin->rp, ftol(rwin->sx(rwin, a->min)), rwin->rp->cp_y);
X }
X if (a->cstep != NOVAL)
X {
X /* Draw ticks and numbers */
X if (a->log)
X {
X /* logarithmic ax */
X double nax;
X int emin, emax, e, count, i;
X
X /* Normalise origin (0 < nax < 10). There will be count ticks,
X at nax, nax + cstep, nax + 2 * cstep, etc for every exponent
X
X value between min & max */
X nax = xorig * pow(10.0, -floor(log10(xorig)));
X /* Exponent range */
X emin = floor(log10(a->min / nax));
X emax = ceil(log10(a->max / nax));
X /* Number of ticks for every exponent value */
X count = ceil(9 * nax / a->cstep);
X
X for (e = emin; e <= emax; e++)
X {
X double const p = pow(10.0, (double)e);
X double const st = a->cstep * p; /* step between ticks */
X double x = p * nax; /* POos. of main tick */
X long cx, cy;
X
X /* Display main value (at nax, with exponent) */
X if (a->every != INOVAL && x != xorig)
X {
X if (y_ax)
X RMove(rwin, a->ax, x);
X else
X RMove(rwin, x, a->ax);
X
X cx = rp->cp_x; cy = rp->cp_y;
X
X if (e == 0)
X {
X /* don't display 10^0 */
X char nb[NBLEN];
X int l;
X
X /* Display nax */
X double2str(nb, nax);
X l = strlen(nb);
X if (y_ax)
X Move(rp, cx + xtext, cy + digits->tf_Baseline /
X 2);
X else
X Move(rp, cx - digits->tf_XSize * l / 2, cy + di
Xgits->tf_Baseline + ytext);
X Text(rp, nb, l);
X }
X else
X {
X char nb[NBLEN + 3], expo[NBLEN];
X int l1, l2;
X
X if (nax == 1)
X strcpy(nb, "10");
X else
X {
X double2str(nb, nax);
X strcat(nb, "*10");
X }
X sprintf(expo, "%d", e);
X l1 = strlen(nb);
X l2 = strlen(expo);
X /* Display base */
X if (y_ax)
X Move(rp, cx + xtext, cy + digits->tf_Baseline /
X 2);
X else
X Move(rp, cx, cy + digits->tf_Baseline + digits-
X>tf_Baseline / 2 + ytext);
X Text(rp, nb, l1);
X /* Display exponent */
X Move(rp, rp->cp_x, rp->cp_y - digits->tf_Baseline /
X 2);
X Text(rp, expo, l2);
X
X }
X }
X /* Now for the ticks ... */
X for (i = 0; i < count; i++, x += st)
X {
X /* Draw tick */
X if (y_ax)
X RMove(rwin, a->ax, x);
X else
X RMove(rwin, x, a->ax);
X
X cx = rp->cp_x; cy = rp->cp_y;
X
X if (y_ax)
X {
X Move(rp, cx + ytick, cy);
X Draw(rp, cx - ytick, cy);
X }
X else
X {
X Move(rp, cx, cy + xtick);
X Draw(rp, cx, cy - xtick);
X }
X /* Display digits */
X if (i != 0 && a->every != INOVAL && (i % a->every) == 0
X)
X {
X char nb[NBLEN];
X int l;
X
X /* Only display mantissa */
X double2str(nb, nax + i * a->cstep);
X l = strlen(nb);
X if (y_ax)
X Move(rp, cx + xtext, cy + digits->tf_Baseline /
X 2);
X else
X Move(rp, cx - digits->tf_XSize * l / 2 + 1, cy
X+ digits->tf_Baseline + ytext);
X Text(rp, nb, l);
X }
X }
X }
X }
X else
X {
X /* linear ax */
X long count, disp_digits;
X double x;
X
X /* Number of ticks */
X count = ceil((a->min - xorig) / a->cstep);
X /* First tick at which to show value */
X disp_digits = a->every == INOVAL ?
X count - 1 : /* No digits displayed */
X a->every * (long)ceil((a->min - xorig) / (a->cs
Xtep * a->every));
X
X for(x = count * a->cstep + xorig; x <= a->max; x += a->cstep, c
Xount++)
X {
X long cx, cy;
X
X /* Draw tick */
X if (y_ax)
X RMove(rwin, a->ax, x);
X else
X RMove(rwin, x, a->ax);
X
X cx = rp->cp_x; cy = rp->cp_y;
X
X if (y_ax)
X {
X Move(rp, cx + ytick, cy);
X Draw(rp, cx - ytick, cy);
X }
X else
X {
X Move(rp, cx, cy + xtick);
X Draw(rp, cx, cy - xtick);
X }
X
X /* Display digits */
X if (count == disp_digits)
X {
X char nb[NBLEN];
X int l;
X
X /* Next one in every ticks */
X disp_digits += a->every;
X
X if (count != 0) /* Not at origin */
X {
X double2str(nb, x);
X l = strlen(nb);
X if (y_ax)
X Move(rp, cx + xtext, cy + digits->tf_Baseline /
X 2);
X else
X Move(rp, cx - digits->tf_XSize * l / 2, cy + di
Xgits->tf_Baseline + ytext);
X Text(rp, nb, l);
X }
X }
X }
X }
X }
X }
X SetFont(rp, oldfont);
X}
X
X/* Draws directly into the rastport, used internally. allow_mes nust be FALSE
X if called during window refresh */
Xstatic void do_draw(struct graph *g, int allow_mes)
X{
X struct object *o;
X
X if (g->ok && g->io.rw)
X {
X /* Draw axes */
X SetAPen(g->io.rw->rp, 1L);
X if (g->a.ok)
X {
X draw_ax(g, &g->a.x, g->a.y.ax, FALSE);
X draw_ax(g, &g->a.y, g->a.x.ax, TRUE);
X }
X
X /* Draw objects */
X for (o = first(&g->o_list); succ(o); o = succ(o))
X if (o != g->s.current && o->ok) o->draw(o, allow_mes);
X
X /* Current object is always last so that it appears "on top" */
X if (g->s.current && g->s.current->ok) g->s.current->draw(g->s.current,
Xallow_mes);
X }
X}
X
X/* Redraw graph completely */
Xvoid draw_graph(struct graph *g, int allow_mes)
X{
X if (allow_mes) set_title(g);
X
X SetRast(g->io.rw->rp, 0); /* Clear window */
X
X do_draw(g, allow_mes);
X}
X
X/* Redraw graph partially (ref is NULL for no redraw). ref is disposed when
X refresh is done */
Xvoid refresh_graph(struct graph *g, int allow_mes, struct Region *ref)
X{
X if (ref)
X {
X if (g->io.rw)
X {
X /* Setup clipping */
X struct Region *oldRegion = InstallClipRegion(g->io.rw->rp->Layer, r
Xef);
X
X SetRast(g->io.rw->rp, 0);
X do_draw(g, allow_mes);
X
X InstallClipRegion(g->io.rw->rp->Layer, oldRegion);
X }
X DisposeRegion(ref);
X }
X}
X
X/* Returns a region that will fully refresh g.
X (makes a copy of the current region) */
Xstruct Region *full_refresh(struct graph *g)
X{
X struct Region *r;
X
X if ((r = NewRegion()) && g->io.rw)
X {
X struct Region *old = InstallClipRegion(g->io.rw->rp->Layer, NULL);
X
X /* Make copy */
X if (!OrRegionRegion(old, r))
X {
X DisposeRegion(r);
X r = NULL;
X }
X
X InstallClipRegion(g->io.rw->rp->Layer, old);
X }
X return r;
X}
X
X/* Open printer.device */
Xstatic int open_prt(void)
X{
X if (prtport = CreatePort(0L, 0L))
X {
X if (prtio = (struct IODRPReq *)CreateExtIO(prtport, sizeof(struct IODRP
XReq)))
X {
X if (OpenDevice("printer.device", 0, (struct IORequest *)prtio, 0) =
X= 0)
X {
X ped = &((struct PrinterData *)prtio->io_Device)->pd_SegmentData
X->ps_PED;
X prtprefs = &((struct PrinterData *)prtio->io_Device)->pd_Prefer
Xences;
X
X return TRUE;
X }
X DeleteExtIO((struct IORequest *)prtport);
X }
X DeletePort(prtport);
X }
X return FALSE;
X}
X
X/* Close printer device */
Xstatic void close_prt(void)
X{
X CloseDevice((struct IORequest *)prtio);
X DeleteExtIO((struct IORequest *)prtio);
X DeletePort(prtport);
X}
X
X/* Easy access to DumpRPort. wait : DoIO or SendIO ? */
Xstatic void prt_raster(int wait, struct RastPort *rp, struct ColorMap *cm, ULON
XG m, UWORD sx, UWORD sy, UWORD w, UWORD h, LONG dc, LONG dr, UWORD special)
X{
X prtio->io_RastPort = rp;
X prtio->io_ColorMap = cm;
X prtio->io_Modes = m;
X prtio->io_SrcX = sx;
X prtio->io_SrcY = sy;
X prtio->io_SrcWidth = w;
X prtio->io_SrcHeight = h;
X prtio->io_DestCols = dc;
X prtio->io_DestRows = dr;
X prtio->io_Special = special;
X prtio->io_Command = PRD_DUMPRPORT;
X if (wait) DoIO(prtio);
X else SendIO(prtio);
X}
X
X/* Print a slice of the dump to the printer */
Xstatic int prt_slice(struct graph *g, struct RastPort *rp, int w, int h, int y,
X int slice, struct Requester *abreq)
X{
X struct RWindow *old = g->io.rw;
X int ret = FALSE;
X ULONG prtsig = 1 << prtio->io_Message.mn_ReplyPort->mp_SigBit;
X ULONG winsig = 1 << g->io.win->UserPort->mp_SigBit;
X
X /* Create coords for slice */
X g->io.rw = new_RWindow(rp, w, slice,
X 0, y + slice - h, 0, -y,
X g->a.x.min, g->a.y.min, g->a.x.max, g->a.y.max,
X g->a.x.log, g->a.y.log, FALSE);
X if (g->io.rw)
X {
X int done = FALSE;
X
X /* Draw into rastport. Note that it may be > 1024 x 1024 ! */
X BigSetRast(rp, 0);
X do_draw(g, TRUE);
X prt_raster(FALSE, rp, prtcm, 0L, 0, 0, (UWORD)w, (UWORD)slice, w, slice
X, SPECIAL_NOFORMFEED);
X
X do { /* Wait for end of printing or abort */
X Wait(prtsig | winsig);
X if (aborted(abreq))
X {
X done = TRUE;
X ret = FALSE; /* Stop! */
X if (!CheckIO(prtio))
X {
X AbortIO(prtio);
X WaitIO(prtio);
X }
X prtio->io_Error = 0;
X }
X else if (CheckIO(prtio))
X {
X done = TRUE;
X ret = prtio->io_Error == 0;
X }
X } while (!done);
X g->io.rw->delete(g->io.rw);
X }
X else
X nomem(g->io.win);
X g->io.rw = old;
X return ret;
X}
X
X/* Work out the max size for a slice (don't use more than half the largest
X chunk of chip ram). The height must be a multiple of quanta */
Xstatic int get_slice_height(int w, int h, int quanta)
X{
X long use = AvailMem(MEMF_CHIP | MEMF_LARGEST) / 2;
X long min = 2 * RASSIZE(w, quanta);
X long nb = use / min;
X
X if (nb == 0) /* Not much mem ... */ return quanta;
X else if (nb * quanta > h) return h;
X else return nb * quanta;
X}
X
X/* Create a 2 plane Rastport with clipping at its limits (-> Layer) */
Xstatic struct RastPort *alloc_ras(int w, int h)
X{
X struct Layer_Info *li;
X struct BitMap *bm;
X BYTE *data;
X struct Layer *l;
X
X /* Alloc components */
X if (li = NewLayerInfo())
X {
X if (bm = AllocMem(sizeof(struct BitMap), 0L))
X {
X if (data = AllocMem(2 * RASSIZE(w, h), MEMF_CHIP))
X {
X /* Set up data structure */
X InitBitMap(bm, 2, w, h);
X bm->Planes[0] = (PLANEPTR)data;
X bm->Planes[1] = (PLANEPTR)(data + RASSIZE(w, h));
X
X if (l = CreateUpfrontLayer(li, bm, 0, 0, w - 1, h - 1, LAYERSIM
XPLE, NULL))
X return l->rp;
X
X FreeMem(data, 2 * RASSIZE(w, h));
X }
X FreeMem(bm, sizeof(struct BitMap));
X }
X DisposeLayerInfo(li);
X }
X return NULL;
X}
X
X/* Free rastport created by alloc_ras */
Xstatic void free_ras(struct RastPort *rp)
X{
X struct Layer_Info *li = rp->Layer->LayerInfo;
X struct BitMap *bm = rp->BitMap;
X
X DeleteLayer(li, rp->Layer);
X FreeMem(bm->Planes[0], bm->BytesPerRow * bm->Rows * bm->Depth);
X FreeMem(bm, sizeof(struct BitMap));
X DisposeLayerInfo(li);
X}
X
X/* Print graph into a bitmap which is w by h pixels, resolution xdpm, ydpm,
X quanta is the size of the print head (if any, 1 otherwise). dump_slice is
X called for every slice.
X Rem: printing is broken into horizontal slices, according to available
X memory */
Xstatic void prt(struct graph *g, int w, int h, int quanta, int xdpm, int ydpm,
Xprtfunc dump_slice)
X{
X int slice, y, ok = TRUE;
X struct RastPort *rp;
X struct Requester *abreq;
X struct Requester *req;
X struct Memory *m;
X struct Gadget *gl = NULL, *thin;
X char size[NBLEN];
X
X size[0] = '\0';
X
X /* Ask user for print characteristics (pen size) */
X if ((m = NewMemory()) &&
X (req = InitReq(50, 20, 180, 85, m)) &&
X SetReqBorder(req, 1, m) &&
X AddIntuiText(&req->ReqText, "Print Characteristics", 6, 6, m) &&
X (thin = AddRadio(&gl, 0, "Thin", TRUE, SELECTED, RELVERIFY, 2, 11, 20,
X10, 10, m)) &&
X AddRadio(&gl, 0, "Thick,", TRUE, 0, RELVERIFY, 1, 11, 40, 10, 10, m) &&
X
X AddText(&gl, 0, "Size ", FALSE, size, NBLEN, TRUE, 0, RELVERIFY, 128, 4
X1, 32, 10, TRUE, m) &&
X AddBox(&gl, TRUE, "Ok", 0, RELVERIFY | ENDGADGET, 13, 60, 65, 15, FALSE
X, m) &&
X AddBox(&gl, FALSE, "Cancel", 0, RELVERIFY | ENDGADGET, 103, 60, 65, 15,
X FALSE, m))
X {
X SetReqGadgets(req, gl);
X if (DoRequest(req, g, std_ghandler))
X {
X double ptsize = str2double(size);
X
X if ((thin->Flags & SELECTED) || (ptsize > 0.0 && ptsize != NOVAL))
X {
X /* Set up for printing */
X if (set_dpm(g, xdpm, ydpm))
X {
X slice = get_slice_height(w, h, quanta);
X if (rp = alloc_ras(w, slice))
X {
X if (abreq = abort_request(g, "Printing, slice
X "))
X {
X if (thin->Flags & SELECTED) set_thin(g, rp);
X else set_pensize(g, rp, ptsize);
X
X /* Print all the slices */
X for (y = 0; ok && y < h; y += slice)
X {
X char msg[30];
X
X sprintf(msg, "Printing, slice %d of %d", y / sl
Xice + 1, (h + slice - 1) / slice);
X set_abort_msg(abreq, msg);
X ok = dump_slice(g, rp, w, h, y, min(slice, h -
Xy), abreq);
X }
X end_abort_request(abreq);
X }
X else
X message(g, "Abort requester failed", (char *)NULL);
X
X free_ras(rp);
X }
X else
X nomem(g->io.win);
X /* Return to screen */
X set_dpm(g, scr_dpmx, scr_dpmy);
X }
X }
X else
X message(g, "Illegal line size", (char *)NULL);
X }
X }
X Free(m);
X}
X
X/* get max size of printed output */
Xstatic int get_max_size(struct graph *g, int *w, int *h, int *quanta)
X{
X prt_raster(TRUE, g->io.win->RPort, prtcm, 0L, 0, 0, g->io.win->Width, g->io
X.win->Height, LONG_MAX, LONG_MAX, SPECIAL_NOPRINT);
X
X *w = prtio->io_DestCols;
X *h = prtio->io_DestRows;
X /* If length = infinity, use MAXPRINTPAGES pages */
X if (*h == LONG_MAX)
X *h = (ped->ped_YDotsInch * MAXPRINTPAGES * prtprefs->PaperLength) / (pr
Xtprefs->PrintSpacing == SIX_LPI ? 6 : 8);
X *quanta = ped->ped_NumRows;
X
X return prtio->io_Error == 0;
X}
X
X/* Determine size which fits asked for ratio (when no absolute size set in
X preferences) */
Xstatic int get_size(struct graph *g, int *w, int *h, int *quanta)
X{
X if (get_max_size(g, w, h, quanta))
X {
X if (g->ok && g->a.ok && g->a.ratio != NOVAL)
X {
X /* adjust for ratio */
X double r = g->a.ratio /
X fabs((*h / (g->a.y.log ? log10(g->a.y.max / g->a.y.min) : (g->a
X.y.max - g->a.y.min)) * ped->ped_XDotsInch) /
X (*w / (g->a.x.log ? log10(g->a.x.max / g->a.x.min) : (g->a
X.x.max - g->a.x.min)) * ped->ped_YDotsInch));
X
X if (r > 1.0) /* make X smaller */
X *w /= r;
X else /* make Y smaller */
X *h *= r;
X }
X if (*w == 0) *w = 1;
X if (*h == 0) *h = 1;
X return TRUE;
X }
X return FALSE;
X}
X
X/* determine size to use when user has set abs. size in preferences */
Xstatic int get_abs_size(struct graph *g, int *w, int *h, int *quanta)
X{
X if (get_max_size(g, w, h, quanta))
X {
X if (g->ok && g->a.ok && g->a.ratio != NOVAL)
X {
X /* Adjust only if dimension is free (size set to 0) */
X double r = g->a.ratio /
X fabs((*h / (g->a.y.log ? log10(g->a.y.max / g->a.y.min) : (g->a
X.y.max - g->a.y.min)) * ped->ped_XDotsInch) /
X (*w / (g->a.x.log ? log10(g->a.x.max / g->a.x.min) : (g->a
X.x.max - g->a.x.min)) * ped->ped_YDotsInch));
X
X if (r > 1.0 && prtprefs->PrintMaxWidth == 0) /* make X smaller */
X *w /= r;
X else if (r < 1.0 && prtprefs->PrintMaxHeight == 0) /* make Y smalle
Xr */
X *h *= r;
X }
X if (*w == 0) *w = 1;
X if (*h == 0) *h = 1;
X return TRUE;
X }
X return FALSE;
X}
X
X/* Print a graph */
Xvoid prt_graph(struct graph *g)
X{
X int w, h, quanta;
X
X if (g->ok)
X if (open_prt())
X {
X prtprefs->PrintFlags &= ~INTEGER_SCALING; /* We produce nice output
X anyway ! */
X prtprefs->PrintAspect = ASPECT_HORIZ; /* No support for vertical pl
Xots */
X
X switch (prtprefs->PrintFlags & DIMENSIONS_MASK)
X {
X case MULTIPLY_DIMENSIONS: /* Ignored */
X prtprefs->PrintFlags &= ~DIMENSIONS_MASK;
X /* FALLTHROUGH */
X case IGNORE_DIMENSIONS:
X case BOUNDED_DIMENSIONS:
X if (get_size(g, &w, &h, &quanta))
X {
X prtprefs->PrintFlags &= ~DIMENSIONS_MASK;
X prt(g, w, h, quanta, (int)(ped->ped_XDotsInch / INCH),
X(int)(ped->ped_YDotsInch / INCH), prt_slice);
X }
X break;
X
X case ABSOLUTE_DIMENSIONS:
X case PIXEL_DIMENSIONS:
X if (get_abs_size(g, &w, &h, &quanta))
X {
X prtprefs->PrintFlags &= ~DIMENSIONS_MASK;
X prt(g, w, h, quanta, (int)(ped->ped_XDotsInch / INCH),
X(int)(ped->ped_YDotsInch / INCH), prt_slice);
X }
X break;
X }
X if (prtio->io_Error > 0) /* Printer error */
X message(g, "Printer Error", prt_error[prtio->io_Error > MAX_PRT
X_ERROR ? 0 : prtio->io_Error], (char *)NULL);
X close_prt();
X }
X else
X message(g, "Couldn't open printer\n", (char *)NULL);
X}
X
X/* Write slice into body. Must add byteRun1 compression */
Xstatic int write_iffslice(struct BitMap *bm)
X{
X int y, plane;
X
X for (y = 0; y < bm->Rows; y++)
X {
X /* Interleave bit planes */
X for (plane = 0; plane < bm->Depth; plane++)
X if (!fwrite(bm->Planes[plane] + y * bm->BytesPerRow, bm->BytesPerRo
Xw, 1, iff_file))
X return FALSE;
X }
X return TRUE;
X}
X
X/* Draw & write into slice for iff output */
Xstatic int iff_slice(struct graph *g, struct RastPort *rp, int w, int h, int y,
X int slice, struct Requester *abreq)
X{
X struct RWindow *old = g->io.rw;
X int ret = FALSE;
X
X g->io.rw = new_RWindow(rp, w, slice,
X 0, y + slice - h, 0, -y,
X g->a.x.min, g->a.y.min, g->a.x.max, g->a.y.max,
X g->a.x.log, g->a.y.log, FALSE);
X if (g->io.rw)
X {
X BigSetRast(rp, 0);
X do_draw(g, TRUE);
X if (write_iffslice(rp->BitMap))
X {
X if (!aborted(abreq)) ret = TRUE;
X }
X else
X message(g, "Error writing file", (char *)NULL);
X
X g->io.rw->delete(g->io.rw);
X }
X else
X nomem(g->io.win);
X g->io.rw = old;
X return ret;
X}
X
X/* Write ILBM header to file (BMHD, CMAP & start of BODY). Save positions for
X writing sizes */
Xstatic int start_iff(char *name, int w, int h, int xdpi, int ydpi)
X{
X if (iff_file = fopen(name, "w"))
X {
X if (fwrite("FORM", 4, 1, iff_file) && (form_pos = ftell(iff_file)) != -
X1L &&
X fwrite("\0\0\0\0ILBMBMHD\0\0\0\024", 16, 1, iff_file))
X {
X static BitMapHeader bm = {
X 0, 0, 0, 0, 2, mskNone, cmpNone, 0, 0
X };
X bm.w = w; bm.h = h;
X bm.xAspect = ydpi; bm.yAspect = xdpi;
X bm.pageWidth = w; bm.pageHeight = h;
X
X if (fwrite((char *)&bm, sizeof(bm), 1, iff_file) &&
X fwrite("CMAP\0\0\0\14", 8, 1, iff_file) &&
X fwrite("\xff\xff\xff\0\0\0\0\0\0\0\0\0", 12, 1, iff_file) &&
X fwrite("BODY", 4, 1, iff_file) && (body_pos = ftell(iff_file))
X!= -1 &&
X fwrite("\0\0\0\0", 4, 1, iff_file))
X {
X return TRUE;
X }
X }
X /* If failed, delete file */
X if (fclose(iff_file) == 0) unlink(name);
X }
X return FALSE;
X}
X
X/* Write end of iff_file, ie pad, write lengths & close */
Xstatic int end_iff(void)
X{
X long end = ftell(iff_file), end2 = end;
X
X if (end != -1)
X {
X if ((end & 1) == 0 || (end2++, fwrite("\0", 1, 1, iff_file))) /* pad. y
Xuck. */
X {
X long formlen = end2 - form_pos - 4; /* Includes pad byte */
X long bodylen = end - body_pos - 4; /* Doesn't */
X
X if (fseek(iff_file, form_pos, 0) != -1 &&
X fwrite((char *)&formlen, sizeof(long), 1, iff_file) &&
X fseek(iff_file, body_pos, 0) != -1 &&
X fwrite((char *)&bodylen, sizeof(long), 1, iff_file))
X {
X return fclose(iff_file) == 0;
X }
X }
X }
X return FALSE;
X}
X
X/* Handle iff requester: display file req when user clicks on disk */
Xstatic int iff_handler(struct Gadget *gg, ULONG class, struct Requester *req, s
Xtruct graph *g)
X{
X if (gg->GadgetID == IFFDISK)
X {
X char file[FILELEN];
X
X if (getfile(file, "IFF Output file"))
X {
X UWORD pos = RemoveGList(req->RWindow, iffg, 1);
X strcpy(iff_filename, file);
X RefreshGList(iffg, req->RWindow, req, 1);
X AddGList(req->RWindow, iffg, pos, 1, req);
X }
X ActivateGadget(iffg, req->RWindow, req);
X return FALSE;
X }
X else return std_ghandler(gg, class, req, g);
X}
X
X/* Output graph as ILBM. Asks for bitmap size, and resolution. Ignores graph
X ratio. */
Xvoid iff_todisk(struct graph *g)
X{
X struct Requester *req;
X struct Memory *m;
X struct Gadget *gl = NULL;
X char xsize[NBLEN], ysize[NBLEN], xdpi[NBLEN], ydpi[NBLEN];
X
X xsize[0] = '\0'; ysize[0] = '\0';
X strcpy(xdpi, "72"); strcpy(ydpi, "72");
X
X iff_filename[0] = '\0';
X if ((m = NewMemory()) &&
X (req = InitReq(50, 20, 280, 110, m)) &&
X SetReqBorder(req, 1, m) &&
X AddIntuiText(&req->ReqText, "Write IFF", 104, 6, m) &&
X (iffg = AddText(&gl, 0, "File ", FALSE, iff_filename, FILELEN, TRUE, 0,
X RELVERIFY, 51, 20, 144, 10, TRUE, m)) &&
X AddBox(&gl, IFFDISK, "Disk", 0, RELVERIFY, 205, 17, 65, 15, FALSE, m) &
X&
X AddText(&gl, 0, "Size: X ", FALSE, xsize, INTLEN, TRUE, 0, RELVERIFY, 7
X5, 45, 32, 10, TRUE, m) &&
X AddText(&gl, 0, "Y ", FALSE, ysize, INTLEN, TRUE, 0, RELVERIFY, 140, 45
X, 32, 10, TRUE, m) &&
X AddText(&gl, 0, "DPI: X ", FALSE, xdpi, INTLEN, TRUE, 0, RELVERIFY, 83,
X 65, 32, 10, TRUE, m) &&
X AddText(&gl, 0, "Y ", FALSE, ydpi, INTLEN, TRUE, 0, RELVERIFY, 140, 65,
X 32, 10, TRUE, m) &&
X AddBox(&gl, TRUE, "Ok", 0, RELVERIFY | ENDGADGET, 38, 85, 65, 15, FALSE
X, m) &&
X AddBox(&gl, FALSE, "Cancel", 0, RELVERIFY | ENDGADGET, 178, 85, 65, 15,
X FALSE, m))
X {
X SetReqGadgets(req, gl);
X if (DoRequest(req, g, iff_handler))
X {
X int w = str2int(xsize);
X int h = str2int(ysize);
X int xdp = str2int(xdpi);
X int ydp = str2int(ydpi);
X
X if (w > 0 && h > 0 && xdp > 0 && ydp > 0 &&
X w != NOVAL && h != NOVAL && xdp != NOVAL && ydp != NOVAL)
X if (start_iff(iff_filename, w, h, xdp, ydp))
X {
X prt(g, w, h, 1, (int)(xdp / INCH), (int)(ydp / INCH), iff_s
Xlice);
X if (!end_iff())
X message(g, "Error writing file", (char *)NULL);
X }
X else
X message(g, "Error writing file", (char *)NULL);
X else
X message(g, "Illegal dimensions !", (char *)NULL);
X }
X }
X Free(m);
X}
X
X/* Write graph to file f */
Xint save_graph(struct graph *g, FILE *f)
X{
X int ok = FALSE;
X short tag = GRAPH_TAG;
X
X /* Write graph information */
X if (WRITE(f, tag) &&
X WRITE(f, g->io.win->LeftEdge) &&
X WRITE(f, g->io.win->TopEdge) &&
X WRITE(f, g->io.win->Width) &&
X WRITE(f, g->io.win->Height) &&
X WRITE(f, g->name) &&
X WRITE(f, g->a))
X {
X struct object *scan;
X
X ok = TRUE;
X /* Write all objects */
X for (scan = first(&g->o_list); ok && succ(scan); scan = succ(scan))
X {
X if (!scan->save(scan, f)) ok = FALSE;
X }
X /* Write end tag */
X if (ok)
X {
X tag = GRAPH_END;
X ok = WRITE(f, tag);
X g->saved = TRUE;
X }
X }
X return ok;
X}
X
X/* Load & create new graph from file f (graph tag already read) */
Xstruct graph *load_graph(struct graph *from, FILE *f)
X{
X struct graph *g = new_graph(from);
X
X if (g)
X {
X WORD leftedge, topedge, width, height;
X int ok = FALSE;
X
X /* Read graph info */
X if (READ(f, leftedge) &&
X READ(f, topedge) &&
X READ(f, width) &&
X READ(f, height) &&
X READ(f, g->name) &&
X READ(f, g->a))
X {
X int done = FALSE;
X
X ok = TRUE;
X do /* Read objects */
X {
X short tag;
X struct object *o = NULL;
X
X if (READ(f, tag))
X switch (tag) /* We have to know which objects exist ... */
X {
X case GRAPH_END:
X done = TRUE;
X break;
X case LABEL_TAG:
X o = (struct object *)load_label(g, f);
X break;
X case FUNCTION_TAG:
X o = (struct object *)load_function(g, f);
X break;
X default:
X message(g, "File is not a graph", (char *)NULL);
X break;
X }
X ok = done || o != NULL;
X if (o)
X add_tail(&g->o_list, o);
X } while (!done && ok);
X
X }
X if (!ok)
X {
X delete_graph(g);
X g = NULL;
X }
X else /* All ok, display */
X {
X check_graph(g);
X g->saved = TRUE;
X }
X }
X return g;
X}
X
X/* Delete a graph */
Xvoid delete_graph(struct graph *g)
X{
X struct object *o, *next;
X
X /* Deselect */
X if (g->s.current) g->s.current->deselect(g->s.current);
X
X /* Delete all objects */
X for (o = first(&g->o_list); next = succ(o); o = next)
X {
X struct Region *ref = o->delete(o);
X
X DisposeRegion(ref);
X }
X
X /* Delete all local resources */
X if (g->io.rw) g->io.rw->delete(g->io.rw);
X CloseFont(g->io.digits);
X cleanup_uio(g); /* Clears menus, closes window ... */
X FreeMem(g, sizeof(struct graph));
X}
X
X/* Create a new graph */
Xstruct graph *new_graph(struct graph *from)
X{
X struct graph *const g = AllocMem(sizeof(struct graph), 0L);
X char *msg;
X const static struct graph def_g = { /* Default values */
X { NULL },
X FALSE, TRUE,
X "Graph",
X { MENUNULL },
X { NULL },
X {
X {
X NOVAL, NOVAL,
X NOVAL, NOVAL,
X INOVAL,
X FALSE
X },
X {
X NOVAL, NOVAL,
X NOVAL, NOVAL,
X INOVAL,
X FALSE
X },
X NOVAL,
X FALSE, FALSE
X },
X {
X FALSE, FALSE,
X NOVAL, NOVAL,
X NULL
X }
X };
X
X if (g)
X {
X *g = def_g;
X g->io.dpmx = scr_dpmx; g->io.dpmy = scr_dpmy;
X new_list(&g->o_list); /* no objects */
X if (g->io.digits = open_font(g, "digits.font", DIGHEIGHT, 0, 0))
X {
X if (init_uio(g)) /* Open window */
X {
X set_scale(g);
X draw_graph(g, TRUE); /* & display */
X return g;
X }
X else msg = "No window";
X CloseFont(g->io.digits);
X }
X else msg = "digits.font missing";
X FreeMem(g, sizeof(struct graph));
X }
X else msg = "No memory !";
X
X message(from, "Couldn't create graph", msg, (char *)NULL);
X
X return NULL;
X}
X
X/* Global initialisation */
Xint init_grph(void)
X{
X struct Screen wbscr;
X
X /* Find screen resolution */
X scr_dpmx = GfxBase->NormalDPMX;
X scr_dpmy = GfxBase->NormalDPMY;
X if (!GetScreenData((char *)&wbscr, sizeof(struct Screen), WBENCHSCREEN, NUL
XL))
X return alert(NULL, "No Workbench !", NULL), FALSE;
X
X if (wbscr.ViewPort.Modes & HIRES) scr_dpmx *= 2;
X if (wbscr.ViewPort.Modes & LACE) scr_dpmy *= 2;
X
X /* Color map for printer. Add colours ? */
X if (!(prtcm = GetColorMap(4))) return nomem(NULL), FALSE;
X SetRGB4CM(prtcm, 0, 15, 15, 15);
X SetRGB4CM(prtcm, 1, 0, 0, 0);
X SetRGB4CM(prtcm, 2, 0, 0, 0);
X SetRGB4CM(prtcm, 3, 0, 0, 0);
X
X return TRUE;
X}
X
X/* Free any global resources */
Xvoid cleanup_grph(void)
X{
X if (prtcm) FreeColorMap(prtcm);
X}
X
SHAR_EOF
echo "End of archive 4 (of 7)"
# if you want to concatenate archives, remove anything after this line
exit